package com.xulu.romance.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xulu.romance.annotation.UserLoginLog;
import com.xulu.romance.pojo.User;
import com.xulu.romance.service.UserService;
import com.xulu.romance.constants.Constant;
import com.xulu.romance.utils.R;
import com.xulu.romance.utils.TokenUtil;
import com.xulu.romance.vo.UserRegisterVo;
import com.xulu.romance.vo.UserVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

import org.springframework.web.bind.annotation.GetMapping;

/**
 * @version 1.0
 * @Author xiaoxulu
 * @Date 2024/1/13 20:58
 */

@RestController
@CrossOrigin
@RequestMapping("/api/user")
@Api(tags = "用户")
@Slf4j
public class UserController {


    @Autowired
    private UserService userService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("/findAll")
    @ApiOperation("查询所有")
    public R findAll() {
        List<User> userList = userService.list();
        return R.ok().put("userList", userList);
    }

    @GetMapping("/findAll/{currentPage}/{size}")
    @ApiOperation("分页查询")
    public R findPage(@PathVariable Long currentPage, @PathVariable Long size, User condition) {
        // 创建分页对象
        IPage<User> page = new Page<>(currentPage, size);

        // 构建查询条件
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if (condition != null) {
            // 如果条件不为空，添加相应的查询条件
            if (StringUtils.isNotBlank(condition.getUserName())) {
                queryWrapper.like("user_name", condition.getUserName());
            }
        }
        // 根据创建时间降序排序
        queryWrapper.orderByDesc("update_time");

        // 执行分页查询
        IPage<User> userPage = userService.page(page, queryWrapper);

        // 获取查询结果
        List<User> userList = userPage.getRecords();
        long total = userPage.getTotal();


        // 返回结果
        return Objects.requireNonNull(R.ok().put("userList", userList)).put("count", total);
    }

    @GetMapping("/findById/{id}")
    @ApiOperation("根据id查询")
    public R findById(@PathVariable Integer id) {
        User user = userService.getById(id);
        return R.ok().put("user", user);
    }


    @PostMapping("/save")
    @ApiOperation("添加用户")
    public R save(@RequestBody User user) {
        String password = user.getPassword();
        if (StringUtils.isBlank(password)) {
            password = "123456";
        }
        user.setPassword(DigestUtils.md5DigestAsHex((password).getBytes(StandardCharsets.UTF_8)));
        user.setStatus(1);
        try {
            boolean save = userService.save(user);
            if (!save) {
                return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message", Constant.SAVE_FAILURE);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return Objects.requireNonNull(new R().put("code", Constant.SUCCESS_CODE)).put("message", Constant.SAVE_SUCCESS);
    }

    @PostMapping("/update")
    @ApiOperation("更新用户")
    public R update(@RequestBody User user) {
        boolean save = userService.updateById(user);
        if (!save) {
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message", Constant.UPDATE_FAILURE);
        }
        return Objects.requireNonNull(new R().put("code", Constant.SUCCESS_CODE)).put("message", Constant.UPDATE_SUCCESS);
    }

    @DeleteMapping("/delete/{id}")
    @ApiOperation("删除用户")
    public R delete(@PathVariable Integer id) {
        boolean save = userService.removeById(id);
        if (!save) {
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message", Constant.DELETE_FAILURE);
        }
        return Objects.requireNonNull(new R().put("code", Constant.SUCCESS_CODE)).put("message", Constant.DELETE_SUCCESS);
    }

    @PostMapping("/deleteBatch")
    @ApiOperation("批量删除用户")
    public R deleteBatch(@RequestBody List<Integer> ids) {
        boolean save = userService.removeBatchByIds(ids);
        if (!save) {
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message", Constant.DELETE_FAILURE);
        }
        return Objects.requireNonNull(new R().put("code", Constant.SUCCESS_CODE)).put("message", Constant.DELETE_SUCCESS);
    }

    @GetMapping("/export")
    @ApiOperation("导出用户信息")
    public void export(HttpServletResponse response) throws Exception {
        List<User> list = userService.list();
        ExcelWriter writer = ExcelUtil.getWriter(true);
        writer.addHeaderAlias("id", "id");
        writer.addHeaderAlias("userName", "用户名");
        writer.addHeaderAlias("password", "密码");
        writer.addHeaderAlias("nickName", "昵称");
        writer.addHeaderAlias("email", "邮箱");
        writer.addHeaderAlias("phone", "手机");
        writer.addHeaderAlias("avatar", "头像");
        writer.addHeaderAlias("gender", "性别");
        writer.addHeaderAlias("address", "地址");

        writer.setOnlyAlias(true);

        writer.write(list, true);

        // 设置response参数
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        String name = URLEncoder.encode("用户信息", "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + name + ".xlsx");

        ServletOutputStream out = response.getOutputStream();
        writer.flush(out, true);
        out.close();
        writer.close();
    }

    @PostMapping("/import")
    @ApiOperation("导入用户信息")
    public R importUser(MultipartFile file) throws IOException {
        InputStream inputStream = file.getInputStream();
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        List<User> userList = reader.readAll(User.class);
        boolean save = userService.saveBatch(userList);
        if (!save) {
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message", Constant.IMPORT_FAILURE);
        }
        return Objects.requireNonNull(new R().put("code", Constant.SUCCESS_CODE)).put("message", Constant.IMPORT_SUCCESS);
    }


    @PostMapping("/login")
    @ApiOperation("用户登录")
   // @UserLoginLog
    public R login(@RequestBody UserVo userVo) {
        String userName = userVo.getUserName();
        String password = userVo.getPassword();
        if (StringUtils.isBlank(userName) || StringUtils.isBlank(password)) {
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message", Constant.USER_IS_NULL);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name", userName);
        queryWrapper.eq("password", DigestUtils.md5DigestAsHex((password).getBytes(StandardCharsets.UTF_8)));
        queryWrapper.eq("status",1);
        User user = userService.getOne(queryWrapper);
        if (user == null) {
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message", Constant.PASSWORD_IS_ERROR);
        }
        user.setPassword("");
        String token = TokenUtil.getToken(String.valueOf(user.getId()),user.getUserName());

        return Objects.requireNonNull(Objects.requireNonNull(Objects.requireNonNull(new R().put("code", Constant.SUCCESS_CODE)).put("message", Constant.LOGIN_SUCCESS)).put("user", user)).put("token",token);

    }

    @GetMapping("/download")
    @ApiOperation("下载模版")
    public ResponseEntity<Resource> downloadTemplate() throws IOException {
        Resource resource = new FileSystemResource("src/main/resources/templates/用户模版.xlsx");
        String fileName = resource.getFilename();

        return ResponseEntity.ok()
                .contentType(MediaType.parseMediaType("application/vnd.ms-excel"))
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
                .body(resource);
    }


    @PostMapping("/register")
    @ApiOperation("用户注册")
    public R register(@RequestBody UserVo userVo) {
        String userName = userVo.getUserName();
        String password = userVo.getPassword();
        if (StringUtils.isBlank(userName) || StringUtils.isBlank(password)) {
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message", Constant.USER_IS_NULL);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name", userName);
        queryWrapper.eq("password", DigestUtils.md5DigestAsHex((password).getBytes(StandardCharsets.UTF_8)));

        User user = userService.getOne(queryWrapper);
        if (user != null) {
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message", Constant.USER_EXIST);
        }
        user = new User();
        userVo.setPassword(DigestUtils.md5DigestAsHex((password).getBytes(StandardCharsets.UTF_8)));
        userVo.setAvatar("http://119.3.166.164:9000/edc-istudy/edc-istudy_1703336415391.png");
        userVo.setStatus(1);
        BeanUtil.copyProperties(userVo, user, true);
        userService.save(user);
        return Objects.requireNonNull(Objects.requireNonNull(new R().put("code", Constant.SUCCESS_CODE)).put("message", Constant.REGISTER_SUCCESS));

    }

    @PostMapping("/updatePassword")
    @ApiOperation("修改密码")
    public R updatePassword(@RequestBody Map<String,Object> map) {
        String oldPassword = (String) map.get("oldPassword");
        String password = (String) map.get("password");
        Integer id = (Integer) map.get("id");
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id );
        queryWrapper.eq("password", DigestUtils.md5DigestAsHex((oldPassword).getBytes(StandardCharsets.UTF_8)));
        User user = userService.getOne(queryWrapper);
        if (user==null) {
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message", Constant.OLD_PASSWORD_ERROR);
        }

        User userVo=new User();
        userVo.setId(id);
        userVo.setPassword(DigestUtils.md5DigestAsHex((password).getBytes(StandardCharsets.UTF_8)));
        boolean save = userService.updateById(userVo);

        if (!save) {
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message", Constant.UPDATE_FAILURE);
        }
        return Objects.requireNonNull(new R().put("code", Constant.SUCCESS_CODE)).put("message", Constant.UPDATE_SUCCESS);
    }

    @GetMapping("/getUserCount")
    @ApiOperation("用户数量")
    public R getUserCount(){
        long count = userService.count();
        return new R().put("count",count);
    }

    @PostMapping("/front/register")
    @ApiOperation("普通用户注册")
    public R frontRegister(@RequestBody UserRegisterVo userRegisterVo){

        String password = userRegisterVo.getPassword();
        String code = userRegisterVo.getCode();
        String email = userRegisterVo.getEmail();
        String nickName = userRegisterVo.getNickName();
        if (!Objects.equals(stringRedisTemplate.opsForValue().get(email), code)){
            return Objects.requireNonNull(Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message", Constant.CODE_ERROR));
        }
        User user=new User();
        user.setPassword(DigestUtils.md5DigestAsHex((password).getBytes(StandardCharsets.UTF_8)));
        user.setAvatar("http://123.60.165.73:9002/edc-istudy/1.png");
        user.setStatus(2);
        user.setEmail(email);
        user.setNickName(nickName);
        userService.save(user);
        stringRedisTemplate.opsForSet().add("registered_users",email);
        return Objects.requireNonNull(Objects.requireNonNull(new R().put("code", Constant.SUCCESS_CODE)).put("message", Constant.REGISTER_SUCCESS));

    }

    @PostMapping("/front/loginPassword")
    @ApiOperation("普通用户密码登录")
    public R frontLoginPassword(@RequestBody UserRegisterVo userRegisterVo){
        String email = userRegisterVo.getEmail();
        String password = userRegisterVo.getPassword();
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("password", DigestUtils.md5DigestAsHex((password).getBytes(StandardCharsets.UTF_8)));
        queryWrapper.eq("email", email);
        queryWrapper.eq("status",2);
        User user = userService.getOne(queryWrapper);

        if (Boolean.FALSE.equals(stringRedisTemplate.opsForSet().isMember("registered_users", email))){
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message",Constant.USER_NOT_EXIST);
        }else if (user==null){
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message",Constant.PASSWORD_IS_ERROR);
        }

        user.setPassword("");

        String token = TokenUtil.getToken(String.valueOf(user.getId()),user.getUserName());

        return Objects.requireNonNull(Objects.requireNonNull(Objects.requireNonNull(new R().put("code", Constant.SUCCESS_CODE)).put("message", Constant.LOGIN_SUCCESS)).put("user", user)).put("token",token);

    }
    @PostMapping("/front/loginCode")
    @ApiOperation("普通用户验证码登录")
    public R frontLoginCode(@RequestBody UserRegisterVo userRegisterVo){
        String email = userRegisterVo.getEmail();
        String code = userRegisterVo.getCode();

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email", email);
        queryWrapper.eq("status",2);
        User user = userService.getOne(queryWrapper);
        if (Boolean.FALSE.equals(stringRedisTemplate.opsForSet().isMember("registered_users", email))){
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message",Constant.USER_NOT_EXIST);
        }else if (!Objects.equals(stringRedisTemplate.opsForValue().get(email), code)){
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message",Constant.CODE_ERROR);
        }

        user.setPassword("");
        String token = TokenUtil.getToken(String.valueOf(user.getId()),user.getUserName());
        return Objects.requireNonNull(Objects.requireNonNull(Objects.requireNonNull(new R().put("code", Constant.SUCCESS_CODE)).put("message", Constant.LOGIN_SUCCESS)).put("user", user)).put("token",token);

    }


    @PostMapping("/front/forgetPassword")
    @ApiOperation("普通用户忘记密码")
    public R forgetPassword(@RequestBody UserRegisterVo userRegisterVo){
        String email = userRegisterVo.getEmail();
        String code = userRegisterVo.getCode();
        String password = userRegisterVo.getPassword();

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email", email);
        queryWrapper.eq("status",2);
        queryWrapper.eq("password", DigestUtils.md5DigestAsHex((password).getBytes(StandardCharsets.UTF_8)));
        User user = userService.getOne(queryWrapper);
        if (user!=null){
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message",Constant.PASSWORD_REPEAT);
        }else if (!Objects.equals(stringRedisTemplate.opsForValue().get(email), code)){
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message",Constant.CODE_ERROR);
        }
        Integer i = userService.updatePasswordByEmail(DigestUtils.md5DigestAsHex((password).getBytes(StandardCharsets.UTF_8)), email);
        if (i<0){
            return Objects.requireNonNull(new R().put("code", Constant.FAILURE_CODE)).put("message",Constant.UPDATE_FAILURE);

        }
        return Objects.requireNonNull(Objects.requireNonNull(Objects.requireNonNull(new R().put("code", Constant.SUCCESS_CODE)).put("message", Constant.UPDATE_SUCCESS)));

    }

}
